package org.ims.inv.web.action.system;

import java.util.Date;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.ims.inv.model.system.ModelAppRole;
import org.ims.inv.model.system.ModelAppUser;
import org.ims.inv.service.system.ServiceAppUser;
import org.ims.inv.web.action.BaseAppAction;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.util.StringUtils;

import cn.trymore.core.common.Constants;
import cn.trymore.core.log.LogAnnotation;
import cn.trymore.core.util.UtilApp;
import cn.trymore.core.util.UtilString;

/**
 * The action for system login.
 * 
 * @author Jeccy.Zhao
 *
 */
public class SystemLoginAction
extends BaseAppAction
{
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(SystemLoginAction.class);
	
	/**
	 * The key for remember me.
	 */
	private static final String KEY_RememberMe = "RememberAppUser";
	
	/**
	 * The key for spring security cookie
	 */
	private static final String KEY_SPRING_SECURITY_COOKIE = "SPRING_SECURITY_REMEMBER_ME_COOKIE";
	
	/**
	 * The login parameter for user name
	 */
	private static final String PARAM_USER_NAME = "username";
	
	/**
	 * The login parameter for user no
	 */
	private static final String PARAM_USER_NMBR = "userNo";
	
	/**
	 * The login parameter for user password
	 */
	private static final String PARAM_USER_PWD = "password";
	
	/**
	 * The parameter for the checking code.
	 */
	@SuppressWarnings("unused")
	private static final String PARAM_CHECKCODE = "checkCode";
	
	/**
	 * The service for application user.
	 */
	private ServiceAppUser serviceAppUser;
	
	/**
	 * The spring security authentication manager
	 */
	@Resource(name="authenticationManager")
	private AuthenticationManager authenticationManager;
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * User logon.
	 */
	@LogAnnotation(description="用户通过身份验证进入系统",type="登录")
	public ActionForward actionLogon (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		StringBuffer msgBuffer = new StringBuffer();
		
		try
		{
			String userNo = request.getParameter(PARAM_USER_NMBR);
			String userPwd = request.getParameter(PARAM_USER_PWD);
			
			if (UtilString.isNotEmpty(userNo))
			{
				ModelAppUser user = this.serviceAppUser.findByUserNo(userNo);
				if (user != null)
				{
					if (user.getUserStatus().equals(ModelAppUser.STAT_FROZEN))
					{
						msgBuffer.append("账号已被冻结, 请联系管理员进行解冻操作!");
					}
					else
					{
						String encodedPwd = UtilString.encryptSha256(userPwd);
						if (user.getPassword().equalsIgnoreCase(encodedPwd))
						{
							// 更新用戶最後登录时间和IP地址
							String reqIp = UtilApp.getRequetIpAddr(request);
							user.setLastLogonIP(reqIp);
							user.setLastLogonTime(new Date());
							this.serviceAppUser.save(user);
							
							// 初始化权限信息
							String roleIds = user.getUserRole();
							if (UtilString.isNotEmpty(roleIds))
							{
								String[] ids = roleIds.split(",");
								for (String roleId : ids)
								{
									if (!user.containsRole(roleId))
									{
										ModelAppRole role = this.serviceAppRole.get(roleId);
										if (role != null)
										{
											user.getUserRoles().add(role);
										}
									}
								}
							}
							
							// stores the authentication to spring security
							UsernamePasswordAuthenticationToken authToken = 
								new UsernamePasswordAuthenticationToken(user.getUsername(), userPwd);
							SecurityContext securityContext = SecurityContextHolder.getContext();
							if (securityContext.getAuthentication().getDetails() != null)
							{
								authToken.setDetails(securityContext.getAuthentication().getDetails());
							}
							securityContext.setAuthentication(this.authenticationManager.authenticate(authToken));
							SecurityContextHolder.setContext(securityContext);
							
							// initialize user session.
							this.initUserSession(request.getSession(), user);
							
							String rememberMe = request.getParameter("_spring_security_remember_me");
							if (rememberMe != null && "on".equalsIgnoreCase(rememberMe))
							{
								String digest = DigestUtils.md5Hex(userNo + ":" + userPwd + ":" + KEY_RememberMe);
								String cookieValue = new String(Base64.encodeBase64(digest.getBytes()));
								response.addCookie(this.makeValidCookie(request, cookieValue));
							}
							
							return ajaxPrint(response, 
									getSuccessCallback("登录成功.", CALLBACK_TYPE_CLOSE, CURRENT_NAVTABID, null, false));
						}
						else
						{
							msgBuffer.append("输入的密码不正确!");
						}
					}
				}
				else
				{
					msgBuffer.append("该用户不存在!");
				}
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when logon.", e);
			msgBuffer.append(e.getMessage());
		}
		
		return ajaxPrint(response, this.getErrorCallback(msgBuffer.toString()));
	}
	
	/**
	 * Generates an valid cookie.
	 * 
	 * @param request
	 * @param cookieValue
	 * @return
	 */
	private Cookie makeValidCookie (HttpServletRequest request, String cookieValue)
	{
		Cookie localCookie = new Cookie(KEY_SPRING_SECURITY_COOKIE, cookieValue);
		
		localCookie.setMaxAge(157680000);
		
		if (StringUtils.hasLength(request.getContextPath()))
		{
			localCookie.setPath(request.getContextPath());
		}
		else
		{
			localCookie.setPath("/");
		}
		
		return localCookie;
	}
	
	/**
	 * Initialization user session.
	 * 
	 * @param session
	 * @param user
	 */
	private void initUserSession (HttpSession session, ModelAppUser user)
	{
		// session injection on user name.
		session.setAttribute(Constants.SESSION_KEY_USER_NAME, user.getUsername());
		
		// session injection on user id
		session.setAttribute(Constants.SESSION_KEY_USER_ID, user.getId());
		
		// session injection on user employee id
		session.setAttribute(Constants.SESSION_KEY_USER_EMPID, user.getUserNo());
		
		if (user.isSuperUser())
		{
			session.setAttribute(Constants.SESSION_KEY_USER_POSITION, "超级管理员");
		}
		else if(user.getUserRole() != null)
		{
			session.setAttribute(Constants.SESSION_KEY_USER_POSITION, user.getRoleName());
		}
		else 
		{
			session.setAttribute(Constants.SESSION_KEY_USER_POSITION, "暂无职位");
		}
	}
	
	public void setAuthenticationManager(AuthenticationManager authenticationManager)
	{
		this.authenticationManager = authenticationManager;
	}

	public AuthenticationManager getAuthenticationManager()
	{
		return authenticationManager;
	}

	public static Logger getLogger()
	{
		return LOGGER;
	}

	public void setServiceAppUser(ServiceAppUser serviceAppUser)
	{
		this.serviceAppUser = serviceAppUser;
	}

	public ServiceAppUser getServiceAppUser()
	{
		return serviceAppUser;
	}

	public static String getParamUserName()
	{
		return PARAM_USER_NAME;
	}
	
}
